package com.zzhua.quartz;

import com.zzhua.entity.SysJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashSet;

@Service
@Slf4j
public class JobTask {

    @Autowired
    SchedulerFactoryBean schedulerFactoryBean;

    /**
     * true 存在 false 不存在
     *
     * @param
     * @return
     */
    public boolean checkJob(SysJob job) {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getId(), Scheduler.DEFAULT_GROUP);
        try {
            // 根据SysJob的 id + "default" ,作为triggerKey; 检查该triggerKey是否存在
            if (scheduler.checkExists(triggerKey)) {
                return true;
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 开启
     */
    public boolean startJob(SysJob job) {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        try {
            Class clazz = Class.forName(job.getClazzPath());
            JobDetail jobDetail = JobBuilder.newJob(clazz).build();
            // 触发器
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getId(), Scheduler.DEFAULT_GROUP);
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(job.getCron())).build();
            // scheduleJob: 验证scheduler的状态,如果关闭了，那么就会抛出异常
            scheduler.scheduleJob(jobDetail, trigger); 
            // 启动
            if (!scheduler.isShutdown()) { // 如果scheduler没有关闭的话
                scheduler.start();
                log.info("---任务[" + triggerKey.getName() + "]启动成功-------");
                return true;
            } else { 
                // 如果scheduler的closed属性是关了的状态的话, 
                // 看不懂这个逻辑: 如果scheduler关闭了的话，那么上面语句就会抛出异常，就不会走这句代码
                // 所以这句话根本就不会执行
                log.info("---任务[" + triggerKey.getName() + "]已经运行，请勿再次启动-------"); 
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return false;
    }

    /**
     * 更新
     * 
     */
    // 根据前面的逻辑来，其实根本就不用这个方法了，只要是要修改，那么你就不能修改正在启动的定时任务，
    // 但是quartz是支持直接修改正在运行的定时任务的。
    // 下面还是分析看一下这个方法做了哪些事
    public boolean updateJob(SysJob job) {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        String createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
		
        // 拿到Triggerkey
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getId(), Scheduler.DEFAULT_GROUP);
        try {
            // scheduler中是否存在triggerkey
            if (scheduler.checkExists(triggerKey)) {
                return false;
            }
			// jobkey和triggerkey同组同名,都是job的id + "default",并且参数都是从数据库中拿到的
            JobKey jobKey = JobKey.jobKey(job.getId(), Scheduler.DEFAULT_GROUP);
			// 拿到Sysjob的cron表达式，定义任务失败策略，生成新的trigger触发器，
            //                                            triggerkey标识就用的跟jobkey一样
            CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(job.getCron())
                    .withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                    .withDescription(createTime).withSchedule(schedBuilder).build();

            // scheduler根据jobkey拿到对应的jobdetail对象
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            HashSet<Trigger> triggerSet = new HashSet<>();
            triggerSet.add(trigger);
            // scheduler把拿到的原来的jobdetail对象和新创建的触发器调度起来
            // 第三个参数必须设置为true，如果不为true的话，
            // 那么如果原来已经存在jobkey或者triggerkey的话,就会抛出异常.
            scheduler.scheduleJob(jobDetail, triggerSet, true);
            log.info("---任务[" + triggerKey.getName() + "]更新成功-------");
            return true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 删除
     */
    public boolean remove(SysJob job) {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getId(), Scheduler.DEFAULT_GROUP);
        try {
            if (checkJob(job)) {
                scheduler.pauseTrigger(triggerKey);
                scheduler.unscheduleJob(triggerKey);
                scheduler.deleteJob(JobKey.jobKey(job.getId(), Scheduler.DEFAULT_GROUP));
                log.info("---任务[" + triggerKey.getName() + "]删除成功-------");
                return true;
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return false;
    }
}
